const WebSocket = require("./websocket")
const event = require("./event")
const UUID = require('uuid');
const JSONbig = require('json-bigint');
const EventEmitter = require('events');
const db = require("./db")

module.exports = class {
    url = ""
    connectionPool= []
    emitter = new EventEmitter()
    dbs = {}

    constructor(url) {
        this.url = url;
        for(var i = 0; i < 16; i++){
            new WebSocket(this)
        }
    }

    send(event, args){
        //得到一个可用的链接
        return new Promise((resolve, reject) => {
            this._getConnection()
                .then(conn => {
                    var ack = UUID.v1();
                    //register event
                    var callback =  (res) => {
                        this.emitter.off(ack, callback)
                        // resolve
                        var obj = JSONbig.parse(res)
                        if (obj == null) {
                            reject(new Error("错误"))
                            return
                        }
                        if(obj.code !== 0){
                            reject(new Error("错误"))
                            return
                        }
                        resolve(obj.data)
                        // return obj.data;
                    };
                    this.emitter.once(ack, callback);
                    setTimeout(() => {
                        this.emitter.off(ack, callback)
                    }, 30000)

                    //send message
                    conn.send(`${event} ${ack} ${JSONbig.stringify(args)}`)
                    this.connectionPool.push(conn)
                })
                .catch(e => {
                    resolve(null)
                });
        });
    }
    _getConnectionFromPool(){
        if(this.connectionPool.length) {
            return this.connectionPool.shift();
        }
        return null;
    }

    _getConnection(){
        return new Promise( (resolve, reject) => {
            var conn = this._getConnectionFromPool();
            if (conn != null) {
                resolve(conn)
                return
            }
            var callback = () => {
                this.emitter.off(event.GET_CONNECTION, callback)
                conn = this._getConnectionFromPool()
                if (conn != null) {
                    resolve(conn);
                    return
                }
                reject()
            };
            this.emitter.on(event.GET_CONNECTION, callback);
            //30s timeout
            setTimeout(() => {
                this.emitter.off(event.GET_CONNECTION, callback)
                reject()
            }, 30000)
        })
    }

    db(dbName){
        return this.dbs[dbName] || (this.dbs[dbName] = new db(this, dbName))
    }

    async show(){
        return await this.send(event.COMMAND_SHOW_DBS, {})
    }
}

